package org.elastic.compreplatform.crawler.util;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.net.URLConnection;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.elastic.compreplatform.crawler.model.CraIpProxy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * ClassName: HttpclientUtil 
 * @Description:  httpclient处理http请求和https请求
 * @author JornTang
 * @date 2018年3月7日
 */
public class HttpclientUtil {
	private static Logger log = LoggerFactory.getLogger(HttpclientUtil.class);
	/**
	 * @Description 处理http请求的post方法
	 * @param url
	 *            :url
	 * @param params
	 *            :参数
	 * @return 返回的字符串
	 */
	public static HttpEntity post(String url, Hashtable<String, String> params) {
		CloseableHttpClient httpClient = null;
		HttpPost httpPost = null;
		String result = "";
		try {
			httpClient = HttpClients.createDefault();
			RequestConfig requestConfig = RequestConfig.custom()
					.setSocketTimeout(4000).setConnectTimeout(4000).build();
			httpPost = new HttpPost(url);
			httpPost.setConfig(requestConfig);
			List<NameValuePair> ps = new ArrayList<NameValuePair>();
			for (String pKey : params.keySet()) {
				ps.add(new BasicNameValuePair(pKey, params.get(pKey)));
			}
			httpPost.setEntity(new UrlEncodedFormEntity(ps, "utf-8"));
			CloseableHttpResponse response = httpClient.execute(httpPost);
			return response.getEntity();
		} catch (ClientProtocolException e) {
		} catch (IOException e) {
		} finally {
			try {
				if (httpPost != null) {
					httpPost.releaseConnection();
				}
				if (httpClient != null) {
					httpClient.close();
				}
			} catch (IOException e) {
			}
		}
		return null;
	}

	/**
	 * @Description 处理http请求的get方法
	 * @param url
	 *            :url
	 * @param params
	 *            :参数
	 * @return 返回的字符串
	 */
	public static HttpEntity get(String url, Hashtable<String, String> params) {
		CloseableHttpClient httpClient = null;
		HttpGet httpGet = null;

		String result = "";
		try {
			httpClient = HttpClients.createDefault();
			RequestConfig requestConfig = RequestConfig.custom()
					.setSocketTimeout(4000).setConnectTimeout(4000).build();
			String ps = "";
			if(params!= null) {
				for (String pKey : params.keySet()) {
					if (!"".equals(ps)) {
						ps = ps + "&";
					}
					// 处理特殊字符，%替换成%25，空格替换为%20，#替换为%23
					String pValue = params.get(pKey).replace("%", "%25")
							.replace(" ", "%20").replace("#", "%23");
					ps += pKey + "=" + pValue;
				}
			}
			if (!"".equals(ps)) {
				url = url + "?" + ps;
			}
			httpGet = new HttpGet(url);
			httpGet.setConfig(requestConfig);
			CloseableHttpResponse response = httpClient.execute(httpGet);
			return response.getEntity();
		} catch (ClientProtocolException e) {
		} catch (IOException e) {
		} catch (Exception e) {
		} finally {
			try {
				if (httpGet != null) {
					httpGet.releaseConnection();
				}
				if (httpClient != null) {
					httpClient.close();
				}
			} catch (IOException e) {
				result = "";
			}
		}
		return null;
	}

	/**
	 * @Description 处理https请求的post方法
	 * @param url
	 *            :url
	 * @param params
	 *            :参数
	 * @return 返回的字符串
	 */
	public static HttpEntity postSSL(String url, Hashtable<String, String> params) {
		CloseableHttpClient httpClient = null;
		HttpPost httpPost = null;
		try {
			httpClient = (CloseableHttpClient) wrapClient();
			RequestConfig requestConfig = RequestConfig.custom()
					.setSocketTimeout(10000).setConnectTimeout(10000).build();
			httpPost = new HttpPost(url);
			httpPost.setConfig(requestConfig);
			List<NameValuePair> ps = new ArrayList<NameValuePair>();
			if(params!= null) {
				for (String pKey : params.keySet()) {
					ps.add(new BasicNameValuePair(pKey, params.get(pKey)));
				}
			}
			httpPost.setEntity(new UrlEncodedFormEntity(ps, "utf-8"));
			CloseableHttpResponse response = httpClient.execute(httpPost);
			return response.getEntity();
		} catch (ClientProtocolException e) {
		} catch (IOException e) {
		} finally {
			try {
				if (httpPost != null) {
					httpPost.releaseConnection();
				}
				if (httpClient != null) {
					httpClient.close();
				}
			} catch (IOException e) {
			}
		}
		return null;
	}

	/**
	 * @Description 处理https请求的get方法
	 * @param url
	 *            :url
	 * @param params
	 *            :参数
	 * @return 返回的字符串
	 */
	public static HttpEntity getSSL(String url, Hashtable<String, String> params) {
		CloseableHttpClient httpClient = null;
		HttpGet httpGet = null;
		try {
			httpClient = (CloseableHttpClient) wrapClient();
			RequestConfig requestConfig = RequestConfig.custom()
					.setSocketTimeout(-1).setConnectTimeout(-1).build();
			String ps = "";
			if(params!= null) {
				for (String pKey : params.keySet()) {
					if (!"".equals(ps)) {
						ps = ps + "&";
					}
					// 处理特殊字符，%替换成%25，空格替换为%20，#替换为%23
					String pValue = params.get(pKey).replace("%", "%25")
							.replace(" ", "%20").replace("#", "%23");
					ps += pKey + "=" + pValue;
				}
			}
			if (!"".equals(ps)) {
				url = url + "?" + ps;
			}
			httpGet = new HttpGet(url);
			httpGet.setConfig(requestConfig);
			CloseableHttpResponse response = httpClient.execute(httpGet);
			return response.getEntity();
		} catch (ClientProtocolException e) {
			log.error("ClientProtocolException下载异常",e);
		} catch (IOException e) {
			log.error("IOException下载异常",e);
		} catch (Exception e) {
			log.error("Exception下载异常",e);
		} finally {
			try {
				if (httpGet != null) {
					httpGet.releaseConnection();
				}
				if (httpClient != null) {
					httpClient.close();
				}
			} catch (IOException e) {
				log.error("IOException下载异常",e);
			}
		}
		return null;
	}

	/**
	 * @Description 处理http请求的post方法（含有大数据的参数）
	 * @param url
	 *            :url
	 * @param params
	 *            :参数
	 * @return 返回的字符串
	 */
	public static HttpEntity sendPost(String url, Map<String, String> params) {
		CloseableHttpClient httpClient = null;
		HttpPost httpPost = null;
		try {
			httpClient = HttpClients.createDefault();
			RequestConfig requestConfig = RequestConfig.custom()
					.setSocketTimeout(4000).setConnectTimeout(4000).build();
			httpPost = new HttpPost(url);
			httpPost.setConfig(requestConfig);

			List<NameValuePair> ps = new ArrayList<NameValuePair>();
			if(params!= null) {
				for (String pKey : params.keySet()) {
					ps.add(new BasicNameValuePair(pKey, params.get(pKey)));
				}
			}

			Hashtable<String, File> files = new Hashtable<String, File>();
			HttpEntity entity = makeMultipartEntity(ps, files);
			httpPost.setEntity(entity);
			CloseableHttpResponse response = httpClient.execute(httpPost);
			return response.getEntity();
		} catch (ClientProtocolException e) {
		} catch (IOException e) {
			log.error("io异常", e);
		} finally {
			try {
				if (httpPost != null) {
					httpPost.releaseConnection();
				}
				if (httpClient != null) {
					httpClient.close();
				}
			} catch (IOException e) {
			}
		}
		return null;
	}

	/**
	 * @Description 处理https请求的post方法（含有大数据的参数）
	 * @param url
	 *            :url
	 * @param params
	 *            :参数
	 * @return 返回的字符串
	 */
	public static String postMultipartSSL(String url,
			Hashtable<String, String> params) {
		CloseableHttpClient httpClient = null;
		HttpPost httpPost = null;
		String result = "";
		String fileName = "";
		try {
			httpClient = (CloseableHttpClient) wrapClient();
			RequestConfig requestConfig = RequestConfig.custom()
					.setSocketTimeout(4000).setConnectTimeout(4000).build();
			httpPost = new HttpPost(url);
			httpPost.setConfig(requestConfig);

			List<NameValuePair> ps = new ArrayList<NameValuePair>();
			for (String pKey : params.keySet()) {
				ps.add(new BasicNameValuePair(pKey, params.get(pKey)));
			}

			Hashtable<String, File> files = new Hashtable<String, File>();
			String content = params.get("Report");
			File file = new File(fileName);
			files.put("Report", file);
			HttpEntity entity = makeMultipartEntity(ps, files);
			httpPost.setEntity(entity);
			CloseableHttpResponse response = httpClient.execute(httpPost);
			HttpEntity httpEntity = response.getEntity();
			return EntityUtils.toString(httpEntity, "utf-8");

		} catch (ClientProtocolException e) {
			result = "";
		} catch (IOException e) {
			result = "";
		} finally {
			try {
				if (httpPost != null) {
					httpPost.releaseConnection();
				}
				if (httpClient != null) {
					httpClient.close();
				}
			} catch (IOException e) {
				result = "";
			}
		}
		return result;
	}

	/**
	 * @Description 创建一个不进行正式验证的请求客户端对象 不用导入SSL证书
	 * @return HttpClient
	 */
	public static HttpClient wrapClient() {
		try {
			SSLContext ctx = SSLContext.getInstance("TLS");
			X509TrustManager tm = new X509TrustManager() {
				public X509Certificate[] getAcceptedIssuers() {
					return null;
				}

				public void checkClientTrusted(X509Certificate[] arg0,
						String arg1) throws CertificateException {
				}

				public void checkServerTrusted(X509Certificate[] arg0,
						String arg1) throws CertificateException {
				}
			};
			ctx.init(null, new TrustManager[] { tm }, null);
			SSLConnectionSocketFactory ssf = new SSLConnectionSocketFactory(
					ctx, NoopHostnameVerifier.INSTANCE);
			CloseableHttpClient httpclient = HttpClients.custom()
					.setSSLSocketFactory(ssf).build();
			return httpclient;
		} catch (Exception e) {
			return HttpClients.createDefault();
		}
	}

	/**
	 * @Description 创建一个HTTPEntity对象
	 * @param params
	 *            :字符串的入参
	 * @param files
	 *            :大数据的入参
	 * @return HttpClient
	 */
	public static HttpEntity makeMultipartEntity(List<NameValuePair> params,
			Map<String, File> files) {

		MultipartEntityBuilder builder = MultipartEntityBuilder.create();
		builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE); // 如果有SocketTimeoutException等情况，可修改这个枚举
		if (params != null && params.size() > 0) {
			for (NameValuePair p : params) {
				builder.addTextBody(p.getName(), p.getValue(),
						ContentType.TEXT_PLAIN.withCharset("UTF-8"));
			}
		}

		if (files != null && files.size() > 0) {
			Set<Entry<String, File>> entries = files.entrySet();
			for (Entry<String, File> entry : entries) {
				builder.addPart(entry.getKey(), new FileBody(entry.getValue()));
			}
		}

		return builder.build();

	}
	/**
	 * @Description: 发送get请求
	 * @param reqURL
	 * @return
	 * @throws ESSearchException   
	 * @return String  
	 * @author JornTang
	 * @throws IOException 
	 * @date 2017年12月27日
	 */
    public static URLConnection get(String reqURL) throws IOException {  
        URL realUrl = new URL(reqURL);  
        // 打开和URL之间的连接  并设置代理
        CraIpProxy proxy = AnalyUtil.getCraIpProxy();
        Proxy urlproxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxy.getProxyIp(), proxy.getProxyPort()));
        URLConnection connection = realUrl.openConnection(urlproxy);  
        // 设置通用的请求属性  
        connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
        connection.setRequestProperty("accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8");  
        connection.setRequestProperty("connection", "keep-alive");  
        connection.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36");  
        connection.setConnectTimeout(20000);  
        connection.setReadTimeout(60 * 60 * 3 * 1000);
        // 建立实际的连接  
        connection.connect(); 
        return connection;
    }
	/**
	 * @param args
	 * @throws IOException 
	 * @throws UnsupportedOperationException 
	 */
	public static void main(String[] args) throws UnsupportedOperationException, IOException {
		//https://vid4-l3.xvideos-cdn.com/videos/3gp/1/f/1/xvideos.com_1f19032c0b5f7b1783f9f9066f6f967b.mp4?e=1520491099&ri=1024&rs=85&h=240c148035cbb03908fbe307de51656c
		String url = "https://vid4-l3.xvideos-cdn.com/videos/3gp/1/f/1/xvideos.com_1f19032c0b5f7b1783f9f9066f6f967b.mp4?e=1520489292&ri=1024&rs=85&h=4d78f251731d65a072a130c8d2cffa18";
		//HttpUtil.downloadFile(url, new File("H:\\data\\111.mp4"));
		//HttpEntity httpEntity = 
		//long length = httpEntity.getContentLength();
		//InputStream stream = httpEntity.getContent();
		//inputstreamToFile(stream, new File("H:\\data\\111.mp4"));
		//System.err.println(length);
	}
}
